package com.demo.aspect;

import com.demo.annotations.Priv;
import com.demo.controller.UserController;
import com.demo.enums.Role;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.util.Arrays;

//@Component
//@Aspect
public class PrivAspect {

    private static final Logger logger = LoggerFactory.getLogger(PrivAspect.class);

    @Pointcut("execution(* com.demo.service..*.*(..))")
    private void pri(){

    }

    // 方法一：
    @Around("pri()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        //获取目标方法
        MethodSignature m = (MethodSignature) pjp.getSignature();
        Method infmethod = m.getMethod();//这个获取到的是UserService接口中的方法   而目标方法应该在UserServicImpl类里的方法

        //获取目标对象---UserServicImpl
        Object target = pjp.getTarget();
        Class<?> clz = target.getClass();

        //获取目标对象类中目标方法（目标方法和之前获取的UserService接口中的方法的方法签名一致）
        //infmethod.getName():获取方法名
        //infmethod.getParameterTypes() ：获取所有的参数
        Method insMethod = clz.getMethod(infmethod.getName(), infmethod.getParameterTypes());

        //判断目标方法身上是否有指定注解---@Priv
        if (insMethod.isAnnotationPresent(Priv.class)) {
            //获取用户角色
            Role role = UserController.role;
            //获取目标方法身上需要角色
            Priv priv = insMethod.getAnnotation(Priv.class);
            Role[] roles = priv.value();
            //检查是否匹配
            //把数组转成List集合，调用集合中contains来判断集合中是否有包含指定内容
            if (Arrays.asList(roles).contains(role)) {
                //匹配执行目标方法
                return pjp.proceed();
            } else {

                logger.info("当前用户权限为:"+role+"该操作权限需要:"+ Arrays.toString(roles) +
                        "该用户权限不足，无法访问！！！");
                //不匹配就抛出异常
                throw new RuntimeException("权限不足，无法访问！！！");
            }
        } else {
            //目标方法上没有注解直接执行目标方法
            return pjp.proceed();
        }
    }
} 
